import pandas as pd
import numpy as nm

import utils


# 基于权重分配矩阵，计算出增强后的结果。
# 本算法包括两个步骤，随机增强和稀疏增强，需要对比它们各自对数据增强的效果，以及合起来的效果
# 所以共计要输出三种增强结果
# 1、只用随机增强 random_augment_result
#   对于原始数据集A，在结果计算中，只用随机增强得到的权重矩阵W1，计算得到结果A1。
#   之后在对比模型上分别训练A和A1，得到预测指标P和P1，对比P1是否相比P有所提升。
# 2、只用稀疏增强 sparse_augment_result
#   对于原始数据集A，在结果计算中，只用稀疏增强得到的权重矩阵W2，计算得到结果A2。
#   之后在对比模型上分别训练A和A2，得到预测指标P和P2，对比P2是否相比P有所提升。
# 3、随机+稀疏一起用 both_augment_result
#   对于原始数据集A，在结果计算中，先后使用随机增强和稀疏增强，得到权重矩阵W1+W2，计算得到结果A3。
#   之后在对比模型上分别训练A和A3，得到预测指标P和P3，对比P3是否相比P有所提升。
def result_compute(ra_weights, sparse_weights, interacted_graph):
    # 这里把ra_weights和sparse_weights加起来，得到sum_weights
    # 然后对sum_weights进行重置
    sum_weights = [utils.reset_weight(ra_weights),
                   utils.reset_weight(sparse_weights),
                   utils.reset_weight(ra_weights + sparse_weights)]
    ra_sum_weights_nozero_count = nm.count_nonzero(sum_weights[0])
    print('ra_sum_weights非0元素：', ra_sum_weights_nozero_count)
    sparse_sum_weights_nozero_count = nm.count_nonzero(sum_weights[1])
    print('ra_sum_weights非0元素：', sparse_sum_weights_nozero_count)
    ras_sum_weights_nozero_count = nm.count_nonzero(sum_weights[2])
    print('ras_sum_weights非0元素：', ras_sum_weights_nozero_count)
    # 求三种方法基于用户交互的资源分配结果
    locates = []
    for weights in sum_weights:
        locates.append(nm.matmul(weights, interacted_graph))

    # 将三种处理结果以列表形式存储
    results = []
    for locate in locates:
        results.append(utils.result_append(locate))
    return results


# 保存输出文件结果
# 在输入的csv文件基础上，更新评分，得到新的csv文件
# 基于result里保存的元素值，更新csv里的评分
# csv[user_id][item_id] = result[item_id][user_id] * C
# 如果csv得到的评分值大于5，就截断成5
# C这个参数默认是200，可以改
def result_export(original_interactions, result, data_name, data_num):
    transform_factor = 200
    # 生成传入数据的copy
    df_original = original_interactions.copy()
    # 文件名前缀列表,ms为随机增强（这个之前没弄其他两个增强的时候就这样定的，改的话要改好多文件名），sms为稀疏增强，srms为随机+稀疏
    prefix = ['ms','sms','srms']
    # 循环分别产生三种结果
    for index in range(len(result)):
        # 构建Dataframe方便数据处理
        df_result = pd.DataFrame(
            {'userid': [i[0] for i in result[index]], 'itemid': [i[1] for i in result[index]], 'pre_rating': [i[2] for i in result[index]]})

        # df_original.drop(['rating'],axis=1,inplace=True)
        # merge快速匹配，更新评分
        df_final = pd.DataFrame(pd.merge(df_original, df_result, on=['userid', 'itemid']))
        # 评分数据转列表
        pre_rating = df_final['pre_rating'].values.tolist()
        # 循环对评分数据进行处理，处理后大于5的就变成5，final_rating作为最终评分
        final_rating = []
        for i in pre_rating:
            i = i * transform_factor - transform_factor
            if i > 5:
                i = 5
            final_rating.append(i)
        # 最终评分加入到dataframe中，方便输出成csv
        df_final['pre_rating'] = final_rating
        # print(df_final)
        # df_final.to_csv('file_saved/augment_{}-{}.csv'.format(data_name,data_num),index=None)

        # 转换为方便模型输入的格式
        df_tomodel = df_final.copy()
        df_tomodel.drop(['pre_rating'], axis=1, inplace=True)
        df_tomodel['rating'] = final_rating

        df_tomodel.to_csv('../datasets/{}/{}_{}-{}.csv'.format(data_name, prefix[index], data_name, data_num), index=None)

        # 设置切分范围
        listBins = [0, 0.1, 0.2, 0.3, 0.4,
                    0.5, 0.6, 0.7, 0.8, 0.9,
                    1.0, 1.5, 2.0, 3.0, 10000]

        # 设置切分后对应标签
        listLabels = ['0_0.1', '0.1_0.2', '0.2_0.3', '0.3_0.4', '0.4_0.5',
                      '0.5_0.6', '0.6_0.7', '0.7_0.8', '0.8_0.9', '0.9_1.0',
                      '1.0_1.5','1.5_2.0','2.0_3.0', '3.0以上']
        # 打印切分后的数据分布
        cut_df = pd.cut(df_final['pre_rating'], bins=listBins, labels=listLabels, include_lowest=True)
        cut_df = pd.DataFrame(cut_df)
        print(prefix[index],'的数据分布如下:')
        print(cut_df.apply(pd.value_counts))
